﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Abp.Domain.Entities;
using Abp.UI;
using DHJ.Cost.CostBooking;
using DHJ.Cost.CostBooking.Config;
using DHJ.Cost.Tasks;
using DHJ.Cost.Timing;
using DHJ.Cost.Workshops;
using JetBrains.Annotations;

namespace DHJ.Cost.Excel
{
    public class ExcelHandler
    {
        private const string CostEntityNameSpace = "DHJ.Cost.CostBooking";
        private const string CostConfigsNameSpace = "DHJ.Cost.CostBooking.Config";

        public static void HandleExcelCells(ExcelType type, OccurrenceTime time, List<ExcelCell> cells,
            ICostContext costContext)
        {
            // 根据 ExcelType 获得 对应 Config

            var configName = Enum.GetName(typeof(ExcelType), type) + "_Config";
            var extendName = Enum.GetName(typeof(ExcelType), type) + "_Extend";
            var configFullName = CostConfigsNameSpace + "." + configName;
            var extendFullName = CostConfigsNameSpace + "." + extendName;
            var config = CreateInstanceByName(configFullName) as CostConfig;

            if (config == null)
                throw new UserFriendlyException("没有找到该成本对应的配置文件");

            var extend = CreateInstanceByName(extendFullName) as ICostExtend;

            if (configName == "辅助材料成本_Config")
            {
                ConvertFZCLToCosts(config, type, time, 一维表格Handle(cells), costContext, extend);
            }

            else if (config.HandleType == CostHandleType.间接成本处理)
            {
                ConvertCellsToCosts(config, time, 二维表格Handle(cells), costContext);
            }
            else if (config.HandleType == CostHandleType.直接成本处理)
            {
                ConvertRowsToCosts(config, type, time, 一维表格Handle(cells), costContext, extend);
            }
        }


        public static void ConvertCellsToCosts(CostConfig config, OccurrenceTime time, List<ExcelHandleItem> items,
            ICostContext costContext, [CanBeNull] ICostExtend extend = null)
        {
            var children = config.Children;
            if (children.Count == 1)
                throw new UserFriendlyException("该间接成本缺少子项");

            try
            {
                foreach (var item in items)
                {
                    var costItem = children.FirstOrDefault(e => item.Col.ToString().Contains(e.Title));

                    if (costItem == null)
                        continue;

                    var workShop = (Workshop) Convert.ToInt32(item.Row);
                    var parameters = new List<Object>
                    {
                        new OccurrenceTime(time.Year, time.Month),
                        new CostSubject(item.Row.ToString()),
                        new CostDetail(costItem.Category, costItem.Title, item.Col.ToString().Split(' ')[1],
                            Convert.ToDecimal(item.Value)),
                        workShop,
                        null,
                        null
                    };

                    var cost = CreateInstanceByName(CostEntityNameSpace + ".ActualCost", parameters) as ActualCost;

                    costContext.ActualCostRepository.Insert(cost);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }


        public static void ConvertRowsToCosts(CostConfig config, ExcelType type, OccurrenceTime time,
            List<ExcelHandleItem<List<ExcelHandleItem>>> items, ICostContext costContext, [CanBeNull] ICostExtend extend = null)
        {
            var child = config.Children.First();

            var maps = config.GetAllMap();

            try
            {
                foreach (var item in items)
                {
                    var workShop = (Workshop) Convert.ToInt32(item.Row);
                    var parameters = new List<Object>
                    {
                        new OccurrenceTime(time.Year, time.Month),
                        new CostSubject(item.Row.ToString()),
                        new CostDetail(child.Category, child.Title, child.Code,
                            Convert.ToDecimal(item.Value.FirstOrDefault(e => e.Col.ToString().Trim() == maps["成本"])?.Value.ToString())),
                        workShop,
                        new List<BatchIdentifier>()
                        {
                            new BatchIdentifier(
                                item.Value.FirstOrDefault(e => e.Col.ToString().Trim() ==  maps["条码"])?.Value.ToString(),
                                Convert.ToInt32(item.Value.FirstOrDefault(e => e.Col.ToString().Trim() == maps["条码数量"])?.Value
                                    .ToString()))
                        }
                    };

                    var cost = CreateInstanceByName(CostEntityNameSpace + ".DirectCost", parameters) as DirectCost;

                    if (extend != null)
                    {
                        FieldInfo[] fields = extend.GetType().GetFields(
                            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

                        foreach (var field in fields)
                        {
                            var fieldName = field.Name.Replace("<", "").Replace(">k__BackingField", "");
                            string colName = fieldName;
                            if (maps.ContainsKey(fieldName))
                                colName = maps[fieldName];

                            field.SetValue(extend, item.Value.FirstOrDefault(e => e.Col.ToString().Trim() == colName.Trim())?.Value);
                        }

                        cost.SetData(extend.GetType().Name, extend);
                    }

                    costContext.ActualCostRepository.Insert(cost);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
        public static void ConvertFZCLToCosts(CostConfig config, ExcelType type, OccurrenceTime time,
          List<ExcelHandleItem<List<ExcelHandleItem>>> items, ICostContext costContext, [CanBeNull] ICostExtend extend = null)
        {
            var child = config.Children.First();

            var maps = config.GetAllMap();

            try
            {
                foreach (var item in items)
                {
                    var workShop = (Workshop)Convert.ToInt32(item.Row);
                    var parameters = new List<Object>
                    {
                        new OccurrenceTime(time.Year, time.Month),
                        new CostSubject(item.Row.ToString()),
                        new CostDetail(child.Category, child.Title, child.Code,
                            Convert.ToDecimal(item.Value.FirstOrDefault(e => e.Col.ToString().Trim() == maps["成本"])?.Value.ToString())),
                        workShop,
                        null,
                        null

                    };

                    var cost = CreateInstanceByName(CostEntityNameSpace + ".ActualCost", parameters) as ActualCost;

                    costContext.ActualCostRepository.Insert(cost);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }

        public static object CreateInstanceByName(string fullName, List<Object> parameters = null)
        {
            if (parameters == null || parameters.Count == 0)
            {
                return  Assembly.GetExecutingAssembly().CreateInstance(fullName);
            }
            else
            {
                return Assembly.GetExecutingAssembly().CreateInstance(fullName, true,
                    BindingFlags.Default, null, parameters.ToArray(), null, null);
            }
        }

        private static List<ExcelHandleItem> 二维表格Handle(List<ExcelCell> cells)
        {
            var cols = cells.Where(e => e.R == "1").ToList();
            var rows = cells.Where(e => Convert.ToInt32(e.R) > 1 && e.C == "A").ToList();
            var dataCells = cells.Where(e => Convert.ToInt32(e.R) > 1).ToList();

            var fullCells = new List<ExcelHandleItem>();

            foreach (var cell in dataCells)
            {
                var row = rows.FirstOrDefault(e => e.R == cell.R);

                var col = cols.FirstOrDefault(e => e.C == cell.C);

                var fullCell = new ExcelHandleItem()
                {
                    Cell = cell.Cell,
                    Value = cell.Value,
                    Row = row?.Value,
                    Col = col?.Value
                };

                fullCells.Add(fullCell);
            }

            return fullCells;
        }

        private static List<ExcelHandleItem<List<ExcelHandleItem>>> 一维表格Handle(List<ExcelCell> cells)
        {
        
            var cols = cells.Where(e => e.R == "1").ToList();
            var rows = cells.Where(e => Convert.ToInt32(e.R) > 1 && e.C == "A").ToList();
            var dataCells = cells.Where(e => Convert.ToInt32(e.R) > 1).ToList();


            var rowItems = dataCells.GroupBy(e => e.R).ToList();

            var fullCells = new List<ExcelHandleItem<List<ExcelHandleItem>>>();

            foreach (var item in rowItems)
            {
                var handleItem = new ExcelHandleItem<List<ExcelHandleItem>>
                {
                    Row = rows.FirstOrDefault(e => e.R == item.Key)?.Value
                };

                foreach (var el in item)
                {
                    var row = rows.FirstOrDefault(e => e.R == el.R);

                    var col = cols.FirstOrDefault(e => e.C == el.C);

                    var fullCell = new ExcelHandleItem()
                    {
                        Cell = el.Cell,
                        Value = el.Value,
                        Row = row?.Value,
                        Col = col?.Value
                    };
                    if (handleItem.Value == null)
                        handleItem.Value = new List<ExcelHandleItem>();
                    handleItem.Value.Add(fullCell);
                }

                fullCells.Add(handleItem);
            }

            return fullCells;
        }
    }
}